<template>
  <div>
    <div class="hidden-columns" ref="hiddenColumns">
      <slot></slot>
    </div>
    <table v-if="showHeader" style="width: 100%;" class="hg-sort-table-head" cellspacing="0">
      <thead>
        <th v-for="(columnItem, colIndex) in store.states._columns" :width="columnItem.width" :key="colIndex">
          {{columnItem.label}}
        </th>
      </thead>
    </table>
    <table-body
      ref="tableBody"
      :context="context"
      :store="store"
      :stripe="stripe"
      :row-class-name="rowClassName"
      :row-style="rowStyle"
      :highlight="highlightCurrentRow"
      >
    </table-body>
  </div>
</template>

<script>

import Mousewheel from 'element-ui/src/directives/mousewheel'
import Locale from 'element-ui/src/mixins/locale'
import Migrating from 'element-ui/src/mixins/migrating'

import TableLayout from 'element-ui/packages/table/src/table-layout'

import TableStore from './table-store'
import TableBody from './sort-body'

import { getRowIdentity } from 'element-ui/packages/table/src/util'

const flattenData = function (data) {
  if (!data) return data
  let newData = []
  const flatten = arr => {
    arr.forEach((item) => {
      newData.push(item)
      if (Array.isArray(item.children)) {
        flatten(item.children)
      }
    })
  }
  flatten(data)
  if (data.length === newData.length) {
    return data
  } else {
    return newData
  }
}

let tableIdSeed = 1

export default {

  name: 'ex-sort-table',

  mixins: [Locale, Migrating],

  directives: {
    Mousewheel
  },

  props: {

    autoFill: {
      type: Boolean,
      default: false
    },

    data: {
      type: Array,
      default: function () {
        return []
      }
    },

    size: String,

    width: [String, Number],

    height: [String, Number],

    maxHeight: [String, Number],

    fit: {
      type: Boolean,
      default: true
    },

    stripe: Boolean,

    border: Boolean,

    rowKey: [String, Function],

    context: {},

    showHeader: {
      type: Boolean,
      default: true
    },

    showSummary: Boolean,

    sumText: String,

    summaryMethod: Function,

    rowClassName: [String, Function],

    rowStyle: [Object, Function],

    cellClassName: [String, Function],

    cellStyle: [Object, Function],

    headerRowClassName: [String, Function],

    headerRowStyle: [Object, Function],

    headerCellClassName: [String, Function],

    headerCellStyle: [Object, Function],

    highlightCurrentRow: Boolean,

    currentRowKey: [String, Number],

    emptyText: String,

    expandRowKeys: Array,

    defaultExpandAll: Boolean,

    defaultSort: Object,

    tooltipEffect: String,

    spanMethod: Function,

    selectOnIndeterminate: {
      type: Boolean,
      default: true
    },

    indent: {
      type: Number,
      default: 16
    },

    lazy: Boolean,

    load: Function
  },

  components: {

    TableBody
  },

  methods: {

    getData() {
      return this.$refs['tableBody'].getData()
    },

    getMigratingConfig() {
      return {
        events: {
          expand: 'expand is renamed to expand-change'
        }
      }
    },

    setCurrentRow(row) {
      this.store.commit('setCurrentRow', row)
    },

    toggleRowSelection(row, selected) {
      this.store.toggleRowSelection(row, selected)
      this.store.updateAllSelected()
    },

    toggleRowExpansion(row, expanded) {
      this.store.toggleRowExpansion(row, expanded)
    },

    clearSelection() {
      this.store.clearSelection()
    },

    clearFilter(columnKeys) {
      this.store.clearFilter(columnKeys)
    },

    clearSort() {
      this.store.clearSort()
    },

    handleMouseLeave() {
      this.store.commit('setHoverRow', null)
      if (this.hoverState) this.hoverState = null
    },

    updateScrollY() {
      this.layout.updateScrollY()
      this.layout.updateColumnsWidth()
    },

    handleFixedMousewheel(event, data) {

    },

    handleHeaderFooterMousewheel(event, data) {

    },

    bindEvents() {

    },

    resizeListener() {
      if (!this.$ready) return
      let shouldUpdateLayout = false
      const el = this.$el
      const { width: oldWidth, height: oldHeight } = this.resizeState

      const width = el.offsetWidth
      if (oldWidth !== width) {
        shouldUpdateLayout = true
      }

      const height = el.offsetHeight
      if ((this.height || this.shouldUpdateHeight) && oldHeight !== height) {
        shouldUpdateLayout = true
      }

      if (shouldUpdateLayout) {
        this.resizeState.width = width
        this.resizeState.height = height
        this.doLayout()
      }
    },

    doLayout() {
      // this.layout.updateColumnsWidth()
      // if (this.shouldUpdateHeight) {
      //   this.layout.updateElsHeight()
      // }
    },

    sort(prop, order) {
      this.store.commit('sort', { prop, order })
    },

    toggleAllSelection() {
      this.store.commit('toggleAllSelection')
    },

    getRowKey(row) {
      const rowKey = getRowIdentity(row, this.store.states.rowKey)
      if (!rowKey) {
        throw new Error('if there\'s nested data, rowKey is required.')
      }
      return rowKey
    },

    getTableTreeData(data) {
      const treeData = {}
      const traverse = (children, parentData, level) => {
        children.forEach(item => {
          const rowKey = this.getRowKey(item)
          treeData[rowKey] = {
            display: false,
            level
          }
          parentData.children.push(rowKey)
          if (Array.isArray(item.children) && item.children.length) {
            treeData[rowKey].children = []
            treeData[rowKey].expanded = false
            traverse(item.children, treeData[rowKey], level + 1)
          }
        })
      }
      if (data) {
        data.forEach(item => {
          const containChildren = Array.isArray(item.children) && item.children.length
          if (!(containChildren || item.hasChildren)) return
          const rowKey = this.getRowKey(item)
          const treeNode = {
            level: 0,
            expanded: false,
            display: true,
            children: []
          }
          if (containChildren) {
            treeData[rowKey] = treeNode
            traverse(item.children, treeData[rowKey], 1)
          } else if (item.hasChildren && this.lazy) {
            treeNode.hasChildren = true
            treeNode.loaded = false
            treeData[rowKey] = treeNode
          }
        })
      }
      return treeData
    },

  },

  created() {
    this.tableId = 'hg-sort-table-head_' + tableIdSeed++
    this.debouncedUpdateLayout = _.debounce(this.doLayout, 50)
  },

  updated() {
    if (this.height) {
      this.defaultHeight = this.height
    } else {
      if (this.autoFill) {
        var windowHeight = window.innerHeight

        var tableTop = this.$el.getBoundingClientRect().top

        this.defaultHeight = windowHeight - tableTop - 36

        // this.height = '600px'
      }
    }

    this.$refs['tableBody'].setStyle({
      width: this.bodyWidth,
      height: this.defaultHeight + 'px',
      'overflow-y': 'scroll'
    })
  },

  computed: {
    tableSize() {
      return this.size || (this.$ELEMENT || {}).size
    },

    bodyWrapper() {
      return this.$refs.bodyWrapper
    },

    shouldUpdateHeight() {
      return this.height ||
        this.maxHeight ||
        this.fixedColumns.length > 0 ||
        this.rightFixedColumns.length > 0
    },

    selection() {
      return this.store.states.selection
    },

    columns() {
      return this.store.states.columns
    },

    tableData() {
      return this.store.states.data
    },

    fixedColumns() {
      return this.store.states.fixedColumns
    },

    rightFixedColumns() {
      return this.store.states.rightFixedColumns
    },

    bodyWidth() {
      const { bodyWidth, scrollY, gutterWidth } = this.layout
      return bodyWidth ? bodyWidth - (scrollY ? gutterWidth : 0) + 'px' : ''
    },

    bodyHeight() {
      if (this.height) {
        return {
          height: this.layout.bodyHeight ? this.layout.bodyHeight + 'px' : ''
        }
      } else if (this.maxHeight) {
        return {
          'max-height': this.layout.bodyHeight ? this.layout.bodyHeight + 'px' : ''
        }
      }
      return {}
    },

    fixedBodyHeight() {
      if (this.height) {
        return {
          height: this.layout.fixedBodyHeight ? this.layout.fixedBodyHeight + 'px' : ''
        }
      } else if (this.maxHeight) {
        let maxHeight = this.layout.scrollX ? this.maxHeight - this.layout.gutterWidth : this.maxHeight

        if (this.showHeader) {
          maxHeight -= this.layout.headerHeight
        }

        maxHeight -= this.layout.footerHeight

        return {
          'max-height': maxHeight + 'px'
        }
      }

      return {}
    },

    fixedHeight() {

    }
  },

  watch: {
    height: {
      immediate: true,
      handler(value) {
        this.layout.setHeight(value)
      }
    },

    maxHeight: {
      immediate: true,
      handler(value) {
        this.layout.setMaxHeight(value)
      }
    },

    currentRowKey(newVal) {
      this.store.setCurrentRowKey(newVal)
    },

    data(newVal) {
      this.$refs['tableBody'].setData(newVal)
    },


    expandRowKeys: {
      immediate: true,
      handler(newVal) {
        if (newVal) {
          this.store.setExpandRowKeys(newVal)
        }
      }
    }
  },

  destroyed() {

  },

  mounted() {
    this.bindEvents()
    this.store.updateColumns()
    this.doLayout()

    this.resizeState = {
      width: this.$el.offsetWidth,
      height: this.$el.offsetHeight
    }

    // init filters
    this.store.states.columns.forEach(column => {
      if (column.filteredValue && column.filteredValue.length) {
        this.store.commit('filterChange', {
          column,
          values: column.filteredValue,
          silent: true
        })
      }
    })

    this.$ready = true
  },

  data() {
    const store = new TableStore(this, {
      rowKey: this.rowKey,
      defaultExpandAll: this.defaultExpandAll,
      selectOnIndeterminate: this.selectOnIndeterminate,
      indent: this.indent,
      lazy: this.lazy
    })
    const layout = new TableLayout({
      store,
      table: this,
      fit: this.fit,
      showHeader: this.showHeader
    })
    return {
      layout,
      store,
      isHidden: false,
      renderExpanded: null,
      resizeProxyVisible: false,
      resizeState: {
        width: null,
        height: null
      },
      // 是否拥有多级表头
      isGroup: false,
      scrollPosition: 'left',

      defaultHeight: '0px'
    }
  }
}

</script>
<style>
.hg-sort-table-head th {
  border-bottom: 1px solid #EBEEF5;
  line-height: 32px;
  background-color: #f6f6f6;
  color: #333;
  font-weight: 500;

  border-bottom: 1px solid #ebeef5;
  text-align: left;

  padding: 0px 0px 0px 5px;
  overflow: hidden;
  user-select: none;
}

.hg-sort-table-item table {
  table-layout: fixed !important;
  width: 100%;
}

.hg-sort-table-item td {
  border-bottom: 1px solid #EBEEF5;
  line-height: 32px;
  padding: 0px 0px 0px 5px;
  overflow: hidden;
  user-select: none;
  height: 32px;
}

.hg-sort-table-item td .cell {
  white-space: nowrap;
  overflow: hidden;
  word-wrap: normal;
  text-overflow: ellipsis;
  display: inline-block;
  vertical-align: middle;
  width: 100%;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  position: relative;
  top: 0px;
  box-sizing: content-box;

}

.hg-sort-table-item .current-row {
  background-color: #c7d7f5;

}
</style>
